/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-05-20 17:18:50
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-15 12:40:55
 * @FilePath     : \openchaoji-corelib\evcc\utility\OpenChaoJi_evcc_utility_pilot.c
 * @Description  : 本文件定义EVCC Utility层 Pilot 导引电路识别 模块
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "OpenChaoJi_evcc_utility_pilot.h"

/**
 * @brief 本模块的上下文数据结构
 */
struct OpenChaoJi_evcc_context_utility_pilot {
    int tag;

	/**
     * 本EVCC使用的系统类型, 目前仅支持A/B两类
    */
    enum OpenChaoJi_evcc_gbt27930_type evcc_gbt27930_type;
	/**
	 * hal层句柄
	 */
	OpenChaoJi_hal_handle hal_handle;

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    bool wakeup;                // B类系统 唤醒电动汽车, 闭合Sv进行连接SECC类型判断
    bool permit_charge;         // B类系统 EVCC闭合S2允许充电
#endif

    enum OpenChaoJi_pilot_status_gbt18487_a polt_status_gbt18487_a;
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    enum OpenChaoJi_pilot_status_gbt18487_b polt_status_gbt18487_b;
#endif

    enum OpenChaoJi_secc_gbt27930_type confirmed_secc_type;     // 当前连接的SECC类型

    /**
     * 检测点2/3电压
     */
    int voltage_checkpoint_2;
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    int voltage_checkpoint_3;
#endif
};

/**
 * @brief 初始化
 *
 * @param info 初始化信息
 * @return 成功返回创建的上下文指针，失败返回NULL。
 */
struct OpenChaoJi_evcc_context_utility_pilot * OpenChaoJi_evcc_utility_pilot_init(const struct OpenChaoJi_evcc_create_info_utility_pilot * info)
{
    struct OpenChaoJi_evcc_context_utility_pilot *context = NULL;

    context = (struct OpenChaoJi_evcc_context_utility_pilot *)OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_evcc_context_utility_pilot));
    if(context == NULL)
    {
        return NULL;
    }
    memset(context,0,sizeof(struct OpenChaoJi_evcc_context_utility_pilot));

    context->tag = info->tag;
    context->evcc_gbt27930_type = info->evcc_gbt27930_type;
    context->hal_handle = info->hal_handle;

    OpenChaoJi_evcc_utility_pilot_reset(context);

    return context;
}

/**
 * @brief 销毁
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_evcc_utility_pilot_term(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return -1;
    }

    OpenChaoJi_os_free(context);

    return 0;
}

/**
 * @brief 复位
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_evcc_utility_pilot_reset(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return -1;
    }

    LOG_WARNING("[%d]Pilot Reset", context->tag);

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    context->wakeup = false;
    context->permit_charge = false;
#endif

    context->polt_status_gbt18487_a = OPENCHAOJI_PILOT_STATUS_GBT18487_A_DISCONNECT;
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    context->polt_status_gbt18487_b = OPENCHAOJI_PILOT_STATUS_GBT18487_B_A;
#endif
    context->confirmed_secc_type = OPENCHAOJI_SECC_GBT27930_TYPE_UNKNOWN;

    context->voltage_checkpoint_2 = 0;
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    context->voltage_checkpoint_3 = 0;
#endif

    return 0;
}

/**
 * @brief evcc通过检测点2电压检测到CC1连接, 通过闭合Sv唤醒, 用于判断SECC类型, B类系统需要, A类无此功能
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_evcc_utility_pilot_wakeup_success(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    int ret = -1;
    if(context == NULL)
    {
        return -1;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if(OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        OpenChaoJi_evcc_hal_gbt_b_close_sv(context->hal_handle, 1);
        context->wakeup = true;
        ret = 0;
    }
#endif

    return ret;
}

/**
 * @brief evcc确认连接B类系统, B类系统需要, A类无此功能
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 	成功返回true，失败返回false
 */
bool OpenChaoJi_evcc_utility_pilot_b_confirm_secc_tyep_b(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if(OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        OpenChaoJi_evcc_hal_gbt_b_close_s2p(context->hal_handle,1);

        LOG_WARNING("[%d]Confirm SECC type B", context->tag);
        context->confirmed_secc_type = OPENCHAOJI_SECC_GBT27930_TYPE_B;

        return true;
    }
#endif

    return false;
}


#if ((OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES) && (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES))
/**
 * @brief evcc确认连接A类系统, B类系统需要, A类无此功能
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回true，失败返回false
 */
bool OpenChaoJi_evcc_utility_pilot_b_confirm_secc_tyep_a(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

    if(OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        // TODO: S2切换到RcCp

        LOG_WARNING("[%d]Confirm SECC type A", context->tag);
        context->confirmed_secc_type = OPENCHAOJI_SECC_GBT27930_TYPE_A;

        return true;
    }

    return false;
}
#endif

/**
 * @brief evcc允许充电, B类系统需要, A类无此功能
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 成功返回0，失败返回-1。
 */
int OpenChaoJi_evcc_utility_pilot_b_permit_charge(struct OpenChaoJi_evcc_context_utility_pilot * context, bool permit)
{
    int ret = -1;
    if(context == NULL)
    {
        return -1;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if(OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        OpenChaoJi_evcc_hal_gbt_b_close_s2(context->hal_handle, permit);
        context->permit_charge = true;
        ret = 0;
    }
#endif

    return ret;
}

/**
 * @brief 获取evcc的导引状态, 用于判断是否连接, 是否已经确认可以充电等(导引方式, 数据通信另外判断)
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 已连接返回1，未连接返回0
 */

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
enum OpenChaoJi_pilot_status_gbt18487_a OpenChaoJi_evcc_utility_pilot_status_a(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    enum OpenChaoJi_pilot_status_gbt18487_a status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_UNKNOWN;
    int volt_value = 0;

    if(context == NULL)
    {
        return OPENCHAOJI_PILOT_STATUS_GBT18487_A_UNKNOWN;
    }

    if ((OPENCHAOJI_EVCC_GBT27930_TYPE_A == context->evcc_gbt27930_type)      // EVCC本身是A类系统, 则只能支持A类状态
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    || ((OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type) && (context->confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_A))   // B类EVCC连接了A类SECC
#endif
    )
    {
        volt_value = OpenChaoJi_evcc_hal_gbt_get_vol_checkpoint_2(context->hal_handle);
        if(volt_value >= SYSTEM_A_EVCC_CC2_VOLT_11_2V && volt_value <= SYSTEM_A_EVCC_CC2_VOLT_12_8V)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_DISCONNECT;
        }
        else if(volt_value >= SYSTEM_A_EVCC_CC2_VOLT_5_2V && volt_value <= SYSTEM_A_EVCC_CC2_VOLT_6_8V)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_A_CONNECTED;
        }
    }

    if (status != context->polt_status_gbt18487_a)
    {
        LOG_ALERT("[%d][%d(0.01V)]%s->%s", context->tag, volt_value, enum_names_OpenChaoJi_pilot_status_gbt18487_a(context->polt_status_gbt18487_a), enum_names_OpenChaoJi_pilot_status_gbt18487_a(status));
        context->polt_status_gbt18487_a = status;
    }
    if (volt_value != context->voltage_checkpoint_2)
    {
        LOG_ALERT("[%d]VOLT_CHECKPOINT_2 %d->%d(0.01V)", context->tag, context->voltage_checkpoint_2, volt_value);
        context->voltage_checkpoint_2 = volt_value;
    }

    return status;
}
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
enum OpenChaoJi_pilot_status_gbt18487_b OpenChaoJi_evcc_utility_pilot_status_b(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    enum OpenChaoJi_pilot_status_gbt18487_b status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_UNKNOWN;
    int volt_value = 0;

    if(context == NULL)
    {
        return status;
    }

    if (OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        volt_value = OpenChaoJi_evcc_hal_gbt_get_vol_checkpoint_2(context->hal_handle);

        if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_A_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_A_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_A;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_AP_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_AP_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_Ap;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_B_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_B_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_B;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_C_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_C_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_C;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_D_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_D_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_D;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_2_E_MIN && volt_value < SYSTEM_B_EVCC_CHECKPOINT_2_E_MAX)
        {
            status = OPENCHAOJI_PILOT_STATUS_GBT18487_B_E;
        }
    }

    if (status != context->polt_status_gbt18487_b)
    {
        LOG_WARNING("[%d][%d(0.01V)]%s->%s", context->tag, volt_value, enum_names_OpenChaoJi_pilot_status_gbt18487_b(context->polt_status_gbt18487_b), enum_names_OpenChaoJi_pilot_status_gbt18487_b(status));
        context->polt_status_gbt18487_b = status;
    }
    if (volt_value != context->voltage_checkpoint_3)
    {
        LOG_ALERT("[%d]VOLT_CHECKPOINT_3 %d->%d(0.01V)", context->tag, context->voltage_checkpoint_3, volt_value);
        context->voltage_checkpoint_3 = volt_value;
    }

    return status;
}
#endif

// 枪头连接
bool OpenChaoJi_evcc_utility_pilot_is_secc_connected(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if (OPENCHAOJI_EVCC_GBT27930_TYPE_A == context->evcc_gbt27930_type)
    {
        return (OpenChaoJi_evcc_utility_pilot_status_a(context) == OPENCHAOJI_PILOT_STATUS_GBT18487_A_CONNECTED);
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
        if (context->confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_A)        // B类EVCC连接A类SECC的情况
        {
            return (OpenChaoJi_evcc_utility_pilot_status_a(context) == OPENCHAOJI_PILOT_STATUS_GBT18487_A_CONNECTED);
        }
#endif

        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_evcc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_Ap)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_B)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_C)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_E);
    }
#endif

    return false;
}

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
// 充电机允许充电
bool OpenChaoJi_evcc_utility_pilot_b_is_secc_permit_charge(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

    if (OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
        if (context->confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_A)        // B类EVCC连接A类SECC的情况
        {
            return false;
        }
#endif
        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_evcc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_C)
            || (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D);
    }

    return false;
}

// 充电机和车辆均允许充电
bool OpenChaoJi_evcc_utility_pilot_b_is_all_permit_charge(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if(context == NULL)
    {
        return false;
    }

    if (OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
        if (context->confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_A)        // B类EVCC连接A类SECC的情况
        {
            return false;
        }
#endif
        enum OpenChaoJi_pilot_status_gbt18487_b status = OpenChaoJi_evcc_utility_pilot_status_b(context);

        return (status == OPENCHAOJI_PILOT_STATUS_GBT18487_B_D);
    }

    return false;
}
#endif

/**
 * @brief 获取已经连接的evcc类型
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return 由于EVCC方只能匹配相同类型的EVCC, 所以这里只能返回EVCC相同类型或者Unknown
 */
enum OpenChaoJi_secc_gbt27930_type OpenChaoJi_evcc_utility_pilot_b_connected_secc_type(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if (context == NULL)
    {
        return OPENCHAOJI_SECC_GBT27930_TYPE_UNKNOWN;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if(OPENCHAOJI_EVCC_GBT27930_TYPE_A == context->evcc_gbt27930_type)      // A类EVCC只能连接A类SECC
    {
        return (OpenChaoJi_evcc_utility_pilot_is_secc_connected(context)) ? OPENCHAOJI_SECC_GBT27930_TYPE_A : OPENCHAOJI_SECC_GBT27930_TYPE_UNKNOWN;
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if(OPENCHAOJI_EVCC_GBT27930_TYPE_B == context->evcc_gbt27930_type)
    {
        if (!OpenChaoJi_evcc_hal_gbt_b_is_closed_sv(context->hal_handle))       // B类EVCC在Sv未闭合情况下无法判断SECC类型
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_UNDEFINED;
        }

        // Sv闭合情况下, 通过检测点3电压来判断连接的SECC类型
        int volt_value = OpenChaoJi_evcc_hal_gbt_b_get_vol_checkpoint_3(context->hal_handle);

        if (volt_value >= SYSTEM_B_EVCC_CHECKPOINT_3_CHADEMO_MIN && volt_value <= SYSTEM_B_EVCC_CHECKPOINT_3_CHADEMO_MAX)
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_CHADEMO;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_3_CCS1_MIN && volt_value <= SYSTEM_B_EVCC_CHECKPOINT_3_CCS1_MAX)
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_CCS1;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_3_CCS2_MIN && volt_value <= SYSTEM_B_EVCC_CHECKPOINT_3_CCS2_MAX)
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_CCS2;
        }
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_3_GBT_B_MIN && volt_value <= SYSTEM_B_EVCC_CHECKPOINT_3_GBT_B_MAX)
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_B;
        }
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
        else if(volt_value >= SYSTEM_B_EVCC_CHECKPOINT_3_GBT_A_MIN && volt_value <= SYSTEM_B_EVCC_CHECKPOINT_3_GBT_A_MAX)
        {
            return OPENCHAOJI_SECC_GBT27930_TYPE_A;
        }
#endif
        // if(volt_value >= SYSTEM_B_EVCC_CC3_VOLT_9_47V && volt_value <= SYSTEM_B_EVCC_CC3_VOLT_10_53V)
        // {
        //     return OPENCHAOJI_SECC_GBT27930_TYPE_UNDEFINED;
        // }
    }
#endif

    return OPENCHAOJI_SECC_GBT27930_TYPE_UNKNOWN;
}


/**
 * @brief 获取evcc已经确认的secc类型
 * 		  由于B类系统在进入自检状态前会断开Sv开关, 所以需要通过导引阶段确认对端SECC系统并进行记录
 *
 * @param context 系统上下文指针，包含必要的环境信息。
 * @return B类系统在导引阶段确认的对端SECC系统
 */
enum OpenChaoJi_secc_gbt27930_type OpenChaoJi_evcc_utility_pilot_b_confirmed_secc_type(struct OpenChaoJi_evcc_context_utility_pilot * context)
{
    if (context == NULL)
    {
        return OPENCHAOJI_SECC_GBT27930_TYPE_UNKNOWN;
    }

    return context->confirmed_secc_type;
}
